#include "stdafx.h"
#include "MyActiveHSM.h"
#include "MyPayload.h"
#include "TypeIds.h"
#include "DefaultConfig.h"

namespace CO { namespace MyGroupNamespace { namespace MyPackageNamespace {

MyActiveHSM::MyActiveHSM() :
	//
	// Initialize Base class.
	//
	SpiFoundation::RoomFW::ActiveHSM(reinterpret_cast<QSTATE>(&MyActiveHSM::Initial),
					   PORT_COUNT,
					   SpiFoundation::RoomFW::ActiveObject::PortPriorityArray(&PortPriorities[0], &PortPriorities[PortPrioritiesSize])),
	//
	// TODO:  Initialize attributes.
	//
	myConfigValue_(0)	// TODO:  Initialize attributes to default!
{
}

MyActiveHSM::~MyActiveHSM()
{
}

bool MyActiveHSM::initialize(SpiFoundation::Configuration::ConfigKey& configRoot)
{
	//
	// TODO:  Initialize attributes with configuration settings.  Get key and value
	//		  will create if they don't exist, so be sure everyone uses the same defines
	//		  to avoid spelling errors!
	//
	configRoot.getValue_T(CFG_VAL_PATH_MyIntValue, myConfigValue_);
	return true;
}

SpiFoundation::RoomFW::ObjectId MyActiveHSM::getObjectId(void) const
{
	//
	// TODO:  Return a unique id for your object.
	//
	return OID_MY_ACTIVE_HSM_ID;
}

const char* MyActiveHSM::getObjectName(void) const
{
	//
	// TODO:  Add text for your object name for debugging.
	//
	return "MyActiveHSM";
}

void MyActiveHSM::handle(SpiFoundation::RoomFW::RoomMessageSP message)
{
	MyActiveHSM* me = this;
	try
	{
		ActiveHSM::handle(message);
	}
	DEFAULT_MSG_HSM_CATCH_BLOCKS(PORT_SYSTEM, message, PORT_MY_PORT_1, MyProtocol::OUT_ERROR, ErrorState)
}

void MyActiveHSM::onError(SpiFoundation::ErrorHandling::IError& e)
{
	//
	// TODO: Remove logging and Handle the error.  DEFAULT_HSM_CATCH_BLOCKS already logs.
	//
	G_LOG_1_ERROR("MyActiveHSM::onError(%s)", e.what());
	this->setTimer(0);
}

void MyActiveHSM::onException(std::exception& e)
{
	//
	// TODO: Remove logging and Handle the error.  DEFAULT_HSM_CATCH_BLOCKS already logs.
	//
	G_LOG_1_ERROR("MyActiveHSM::onException(%s)", e.what());
	this->setTimer(0);
}

void MyActiveHSM::onCatchAllException()
{
	//
	// TODO: Remove logging and Handle the error.  DEFAULT_HSM_CATCH_BLOCKS already logs.
	//
	G_LOG_0_ERROR("MyActiveHSM::onCatchAllException()");
	this->setTimer(0);
}

void MyActiveHSM::Initial(MyActiveHSM* me, QEvent const* /*evt*/)
{
	//
	// TODO:  Perform initial transition.
	//
	Q_TRAN(reinterpret_cast<QSTATE>(&MyActiveHSM::StateC));
}

QSTATE MyActiveHSM::StateA(MyActiveHSM* me, QEvent const *evt)
{
	//
	// TODO:  Initialize retVal to parent state.  Set retVal to 0 if you handle the message.
	//
	QSTATE retVal = reinterpret_cast<QSTATE>(&ActiveHSM::top); // Parent of top-level states.

	//
	// Catch all exceptions here.  Any that escape will result in the thread exiting.
	//
	switch (evt->sig)
	{
	case Q_ENTRY_SIG:
		//
		// TODO:  Perform state entry actions.
		//
		G_LOG_0_TRACE("StateA entry");
		retVal = 0;
		break;

	case Q_EXIT_SIG:
		//
		// TODO:  Perform state exit actions.
		//
		G_LOG_0_TRACE("StateA exit");
		retVal = 0;
		break;

	case Q_USER_SIG:
		{
			// Get the room message.  Base class ensures that's what a Q_USER_SIG is.
			SpiFoundation::RoomFW::RoomMessage* message = static_cast<SpiFoundation::RoomFW::RoomMessage*>(const_cast<QEvent*>(evt));
			switch (message->portIndex().port())
			{
			case PORT_SYSTEM:
				{
					//
					// TODO:  Handle system messages.
					//
					switch (message->messageID())
					{
					case SystemManagerProtocol::I_AM_READY:
						{
							//
							// TODO:  Begin collaborative initialization.
							//
							me->sendMessage(message->portIndex(), MyProtocol::I_AM_READY_ACK);
						}
						break;
					//case Protocol::SystemManagerProtocol::UPDATE_CONFIG:
					//	{
					//		Protocol::ConfigKeyPayloadSP payload =
					//			::boost::dynamic_pointer_cast<Protocol::ConfigKeyPayload, SpiFoundation::RoomFW::IPayload>(message->payload());
					//		ASSERT(0 != payload);
					//		SpiFoundation::Configuration::ConfigKey& configRoot = payload->valueRef();
					//		//
					//		// TODO:  Apply updated configuration settings.
					//		//
					//	}
					//	break;
					}
				}
				break;
			case PORT_MY_PORT_1:
				{
					//
					// TODO:  Handle each message message for this port.
					//
					switch (message->messageID())
					{
					case MyProtocol::IN_MESSAGE_1:
						{
							//
							// TODO:  Handle the message.  See StateB and StateC for state transition examples.
							//
							MyPayloadSP msgPayload = ::boost::dynamic_pointer_cast<MyPayload, SpiFoundation::RoomFW::IPayload>(message->releasePayload());
							if (0 != msgPayload)
							{
								me->sendMessage(message->portIndex(),
												MyProtocol::OUT_MESSAGE_1,
												SpiFoundation::RoomFW::IPayload::ReleaseOwnership(msgPayload));
							}
							retVal = 0; // Indicates that message was handled.
						}
						break;
					case MyProtocol::IN_ERROR_1:
						{
							throw SpiFoundation::ErrorHandling::BaseError(
								SpiFoundation::ErrorHandling::EID_FND_UNHANDLED_EXCEPTION,
								SpiFoundation::ErrorHandling::ESEVfatal,
								"Fatal Error");
						}
						break;
					case MyProtocol::IN_ERROR_2:
						{
							throw std::runtime_error("Fatal Exception");
						}
						break;
					case MyProtocol::IN_ERROR_3:
						{
							int* i = 0;
							++(*i);
						}
						break;
					case MyProtocol::IN_ERROR_4:
						{
							me->setTimer(0);
						}
						break;
					case MyProtocol::IN_ERROR_5:
						{
							me->put(
								SpiFoundation::RoomFW::RoomMessageSP(
									new SpiFoundation::RoomFW::RoomMessage(
										(me->timerPortIndex_ + 1), SpiFoundation::RoomFW::INVALID_MESSAGE_ID)));
						}
						break;
					default:
						ASSERT(FALSE); // Already handled all legal messages.  Anything else is an error!
					}
				}
				break;
			case PORT_TIMER: // Handle timer messages.
				{
					SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
					ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
					//
					// TODO:  Handle timer id.
					//
					// Test error handling.
					throw std::runtime_error("Timer Error");
				}
				break;
			default:
				//ASSERT(FALSE); // No more ports!
				// Test error handling.
				throw std::runtime_error("Unexpected Message Error");
			}
		}
	}
	return retVal;
}

QSTATE MyActiveHSM::StateB(MyActiveHSM* me, QEvent const *evt)
{
	//
	// TODO:  Initialize retVal to parent state.  Set retVal to 0 if you handle the message.
	//
	QSTATE retVal = reinterpret_cast<QSTATE>(&MyActiveHSM::StateA); // Parent State.

	switch (evt->sig)
	{
	case Q_ENTRY_SIG:
		//
		// TODO:  Perform state entry actions.
		//
		if (me->isRunning())
		{
			me->sendMessage(PORT_MY_PORT_1, MyProtocol::OUT_MESSAGE_2);
		}
		break;

	case Q_EXIT_SIG:
		//
		// TODO:  Perform state exit actions.
		//
		break;

	case Q_USER_SIG:
		{
			// Get the room message.  Base class ensures that's what a Q_USER_SIG is.
			SpiFoundation::RoomFW::RoomMessage* message = static_cast<SpiFoundation::RoomFW::RoomMessage*>(const_cast<QEvent*>(evt));
			switch (message->portIndex().port())
			{
			case PORT_SYSTEM:
				{
					//
					// TODO:  Handle system messages.
					//
					switch (message->messageID())
					{
					case SystemManagerProtocol::I_AM_READY:
						{
							//
							// TODO:  Begin collaborative initialization.
							//
							me->sendMessage(message->portIndex(), MyProtocol::I_AM_READY_ACK);
						}
						break;
					//case Protocol::SystemManagerProtocol::UPDATE_CONFIG:
					//	{
					//		Protocol::ConfigKeyPayloadSP payload =
					//			::boost::dynamic_pointer_cast<Protocol::ConfigKeyPayload, SpiFoundation::RoomFW::IPayload>(message->payload());
					//		ASSERT(0 != payload);
					//		SpiFoundation::Configuration::ConfigKey& configRoot = payload->valueRef();
					//		//
					//		// TODO:  Apply updated configuration settings.
					//		//
					//	}
					//	break;
					default:
						ASSERT(false);
						break;
					}
				}
				break;
			case PORT_MY_PORT_1:
				{
					//
					// TODO:  Handle each message message for this port.
					//
					switch (message->messageID())
					{
					case MyProtocol::IN_MESSAGE_1:
					case MyProtocol::IN_MESSAGE_2:
						break;	// Handled by parent state.
					case MyProtocol::IN_MESSAGE_3:
						{
							//
							// TODO:  Handle the message.
							//
							Q_TRAN(reinterpret_cast<QSTATE>(&MyActiveHSM::StateC)); // State Transition.
							retVal = 0; // Indicates that message was handled.
						}
						break;
					}
				}
				break;
			case PORT_TIMER: // Handle timer messages.
				{
					SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
					ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
					//
					// TODO:  Handle timer id.
					//
				}
				break;
			default:
				ASSERT(FALSE); // No more ports!
			}
		}
	}
	return retVal;
}

QSTATE MyActiveHSM::StateC(MyActiveHSM* me, QEvent const *evt)
{
	//
	// TODO:  Initialize retVal to parent state.  Set retVal to 0 if you handle the message.
	//
	QSTATE retVal = reinterpret_cast<QSTATE>(&MyActiveHSM::StateA); // Parent State.

	switch (evt->sig)
	{
	case Q_ENTRY_SIG:
		//
		// TODO:  Perform state entry actions.
		//
		if (me->isRunning())
		{
			me->sendMessage(PORT_MY_PORT_1, MyProtocol::OUT_MESSAGE_3);
		}
		break;

	case Q_EXIT_SIG:
		//
		// TODO:  Perform state exit actions.
		//
		break;

	case Q_USER_SIG:
		{
			// Get the room message.  Base class ensures that's what a Q_USER_SIG is.
			SpiFoundation::RoomFW::RoomMessage* message = static_cast<SpiFoundation::RoomFW::RoomMessage*>(const_cast<QEvent*>(evt));
			switch (message->portIndex().port())
			{
			case PORT_SYSTEM:
				{
					//
					// TODO:  Handle system messages.
					//
					switch (message->messageID())
					{
					case SystemManagerProtocol::I_AM_READY:
						{
							//
							// TODO:  Begin collaborative initialization.
							//
							me->sendMessage(message->portIndex(), MyProtocol::I_AM_READY_ACK);
						}
						break;
					//case Protocol::SystemManagerProtocol::UPDATE_CONFIG:
					//	{
					//		Protocol::ConfigKeyPayloadSP payload =
					//			::boost::dynamic_pointer_cast<Protocol::ConfigKeyPayload, SpiFoundation::RoomFW::IPayload>(message->payload());
					//		ASSERT(0 != payload);
					//		SpiFoundation::Configuration::ConfigKey& configRoot = payload->valueRef();
					//		//
					//		// TODO:  Apply updated configuration settings.
					//		//
					//	}
					//	break;
					}
				}
				break;
			case PORT_MY_PORT_1:
				{
					//
					// TODO:  Handle each message message for this port.
					//
					switch (message->messageID())
					{
					case MyProtocol::IN_MESSAGE_1:
					case MyProtocol::IN_MESSAGE_3:
						break;	// Handled by parent state.
					case MyProtocol::IN_MESSAGE_2:
						{
							//
							// TODO:  Handle the message.
							//
							Q_TRAN(reinterpret_cast<QSTATE>(&MyActiveHSM::StateB)); // State Transition.
							retVal = 0; // Indicates that message was handled.
						}
						break;
					}
				}
				break;
			case PORT_TIMER: // Handle timer messages.
				{
					SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
					ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
					//
					// TODO:  Handle timer id.
					//
				}
				break;
			default:
				ASSERT(FALSE); // No more ports!
			}
		}
	}
	return retVal;
}

QSTATE MyActiveHSM::ErrorState(MyActiveHSM* me, QEvent const *evt)
{
	//
	// TODO:  Initialize retVal to parent state.  Set retVal to 0 if you handle the message.
	//
	QSTATE retVal = reinterpret_cast<QSTATE>(&ActiveHSM::top); // Parent State.

	switch (evt->sig)
	{
	case Q_ENTRY_SIG:
		//
		// TODO:  Perform state entry actions.
		//
		G_LOG_0_TRACE("ErrorState entry");
		retVal = 0;
		break;

	case Q_EXIT_SIG:
		//
		// TODO:  Perform state exit actions.
		//
		G_LOG_0_TRACE("ErrorState exit");
		retVal = 0;
		break;
	case Q_USER_SIG:
		{
			// Get the room message.  Base class ensures that's what a Q_USER_SIG is.
			SpiFoundation::RoomFW::RoomMessage* message = static_cast<SpiFoundation::RoomFW::RoomMessage*>(const_cast<QEvent*>(evt));
			switch (message->portIndex().port())
			{
			case PORT_TIMER: // Handle timer messages.
				{
					SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
					ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
					//
					// TODO:  Handle timer id.
					//
					Q_TRAN(StateA);
				}
				break;
			}
		}
	}
	return retVal;
}

}}} // End namespace
